/**
  ETFAna project, Anyang Normal University && IMP-CAS

  \class ETFHPTDCCh
  \brief the class holding the timing data acquired by the HPTDC (@CERN) chip
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2021-09-27
  \date 2021-10-10 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date        <th>Author      <th>Description                    </tr>
  <tr>  <td>2021-09-27   <td>Asia Sun    <td>file created                  </tr>
  </table>

  \copyright Copyright (c) 2021-2024 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/

#include <cmath>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include "ETFHPTDCCh.h"
#include "ETFMsg.h"
#include "ETFMath.h"

using std::cout;
using std::endl;
using std::swap;

// time for one channel of HPTDC HIGH resolution mode: ~100ps
const double ETFHPTDCCh::kH_BLIP = 25. / pow(2., 8.);
// time for one channel of HPTDC VERY HIGH resolution mode: ~25ps
const double ETFHPTDCCh::kV_BLIP = 25. / pow(2., 10.);

ETFHPTDCCh::ETFHPTDCCh() : ETFRawChannel(){
  Initialize();
} // end ctor

ETFHPTDCCh::ETFHPTDCCh(const ETFHPTDCCh &ch) : ETFRawChannel(ch),
vl(ch.vl), vt(ch.vt), fBunchID(ch.fBunchID), fIs_V(ch.fIs_V){}

ETFHPTDCCh::~ETFHPTDCCh(){}

double ETFHPTDCCh::GetLeadingEdge(int i) const{
  if(i < 0 || i >= int(vl.size())){
    // ETFMsg::Warn("ETFHPTDCCh", "GetLeadingEdge: i = %d out of bounds"
    //   "-9999 is returned", i);
    return -999.;
  } // end if
  return vl[i];
} // end member function GetLeadingEdge

double ETFHPTDCCh::GetTrailingEdge(int i) const{
  if(i < 0 || i >= int(vt.size())){
    // ETFMsg::Warn("ETFHPTDCCh", "GetTrailingEdge: i = %d out of bounds"
    //   "-9999 is returned", i);
    return -999.;
  } // end if
  return vt[i];
} // end member function GetTrailingEdge

double ETFHPTDCCh::GetTOT(int i) const{
  const double t = tt(i), l = tl(i);
  if(-999. == t || -999. == l) return -999.;
  return t - l;
} // end member function GetTOT

void ETFHPTDCCh::Reset(){
  // ETFRawChannel::Reset();
  vl.clear(); vt.clear();
  // fIs_V = false;
  // fBunchID = -1;
} // end member function Reset

void ETFHPTDCCh::AddLeadingEdgeV(int l){
  fIs_V = true;
  AddLed((l+rand0_1())*kV_BLIP);
} // end member function AddLeadingEdgeV
void ETFHPTDCCh::AddLeadingEdgeH(int l){
  fIs_V = false;
  AddLed((l+rand0_1())*kH_BLIP);
} // end member function AddLeadingEdgeH
void ETFHPTDCCh::AddTrailingEdgeV(int t){
  fIs_V = true;
  AddTed((t+rand0_1())*kV_BLIP);
} // end member function AddTrailingEdgeV

void ETFHPTDCCh::AddTrailingEdgeH(int t){
  fIs_V = false;
  AddTed((t+rand0_1())*kH_BLIP);
} // end member function AddTrailingEdgeH

// add a leading edge
void ETFHPTDCCh::AddLed(double l){
  vl.push_back(l);
} // end member function AddLed
// add a trailing edge
void ETFHPTDCCh::AddTed(double t){
  vt.push_back(t);
} // end member function AddTed
// intended to subtract trigger time
void ETFHPTDCCh::SubtractTrigger(int bunchID){
  if(-1 == bunchID) return;
  fBunchID = bunchID;
  for(auto &t : vl) t = ETFMath::TimeToTrig(t, bunchID);
  for(auto &t : vt) t = ETFMath::TimeToTrig(t, bunchID);
} // end member functuion SubtractTrigger

// erase i-the element of vl or vt
void ETFHPTDCCh::erase(int i, bool isLeading){
  if(isLeading) vl.erase(vl.begin() + i);
  else vt.erase(vt.begin() + i);
} // end member function erase

void ETFHPTDCCh::Print(const char *) const{
  cout << std::boolalpha << std::fixed << std::setprecision(6);

  cout << "\033[34;1mchannel ID: " << fChannelId << "\n\033[0m";
  cout << "is_V: " << fIs_V << endl;
  int i = 0;
  for(auto &t : vl) cout << "leading edge[" << i++ << "]: " << t << " ns" << endl;
  i = 0;
  for(auto &t : vt) cout << "trailing edge[" << i++ << "]: " << t << " ns" << endl;
  
  // print tot
  const int n = vl.size() < vt.size() ? vl.size() : vt.size();
  for(int j = 0; j < n; j++) cout << "tot[" << j << "]: " << tot(j) << " ns" << endl;

  cout.unsetf(std::ios_base::floatfield);
  cout.unsetf(std::ios_base::boolalpha);
} // end member function Print

// if there're only trailing edges, make them leading ones //
void ETFHPTDCCh::SelfCheck(){
  // if(!vl.size() && vt.size()) swap(vl, vt); // we believe this is right
} // end member function SelfCheck
